package edu.wright.ceg4980.year2013.keyboard;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import javax.swing.JPasswordField;

public class TimedPasswordField extends JPasswordField {
	private PasswordKeyListener passwordKeyListener;
	
	public TimedPasswordField() {
		passwordKeyListener = new PasswordKeyListener(this);
		addKeyListener(passwordKeyListener);
	}
	
	public void reset() {
		setText("");
		passwordKeyListener.clear();
	}
	
	public KeyTimingDataSequence getKeyTimingData() {
		return new KeyTimingDataSequence(passwordKeyListener.getKeyPresses(), passwordKeyListener.getKeyReleases());
	}
	
	private static class PasswordKeyListener extends KeyAdapter {
		private TimedPasswordField timedPasswordField;
		
		private LinkedList<KeyData> keyPresses;
		private LinkedList<KeyData> keyReleases;
		
		public PasswordKeyListener(TimedPasswordField timedPasswordField) {
			this.timedPasswordField = timedPasswordField;
			keyPresses = new LinkedList<KeyData>();
			keyReleases = new LinkedList<KeyData>();
		}
		
		public LinkedList<KeyData> getKeyPresses() {
			return keyPresses;
		}
		
		public LinkedList<KeyData> getKeyReleases() {
			return keyReleases;
		}
		
		public void clear() {
			keyPresses.clear();
			keyReleases.clear();
		}
		
		@Override
		public void keyPressed(KeyEvent e) {
			int keyCode = e.getKeyCode();
			
			switch (keyCode) {
			case KeyEvent.VK_BACK_SPACE:
				timedPasswordField.reset();
				break;
			case KeyEvent.VK_ENTER:
				timedPasswordField.fireActionPerformed();
				break;
			default:
				if (TimedPasswordField.isKeyValid(keyCode)) {
					keyPresses.add(new KeyData(keyCode, e.getWhen()));
					return;
				}
			}
			
			// consume the event to override default behavior for other keys
			e.consume();
		}
		
		@Override
		public void keyReleased(KeyEvent e) {
			int keyCode = e.getKeyCode();
			
			switch (keyCode) {
			case KeyEvent.VK_BACK_SPACE:
			case KeyEvent.VK_ENTER:
				break;
			default:
				if (TimedPasswordField.isKeyValid(keyCode)) {
					keyReleases.add(new KeyData(keyCode, e.getWhen()));
					return;
				}
			}

			// consume the event to override default behavior for other keys
			e.consume();
		}
	}
	
	private static boolean isKeyValid(int keyCode) {
		switch (keyCode) {
		case KeyEvent.VK_SHIFT:
		case KeyEvent.VK_BACK_QUOTE:
		case KeyEvent.VK_1:
		case KeyEvent.VK_2:
		case KeyEvent.VK_3:
		case KeyEvent.VK_4:
		case KeyEvent.VK_5:
		case KeyEvent.VK_6:
		case KeyEvent.VK_7:
		case KeyEvent.VK_8:
		case KeyEvent.VK_9:
		case KeyEvent.VK_0:
		case KeyEvent.VK_MINUS:
		case KeyEvent.VK_EQUALS:
		case KeyEvent.VK_A:
		case KeyEvent.VK_B:
		case KeyEvent.VK_C:
		case KeyEvent.VK_D:
		case KeyEvent.VK_E:
		case KeyEvent.VK_F:
		case KeyEvent.VK_G:
		case KeyEvent.VK_H:
		case KeyEvent.VK_I:
		case KeyEvent.VK_J:
		case KeyEvent.VK_K:
		case KeyEvent.VK_L:
		case KeyEvent.VK_M:
		case KeyEvent.VK_N:
		case KeyEvent.VK_O:
		case KeyEvent.VK_P:
		case KeyEvent.VK_Q:
		case KeyEvent.VK_R:
		case KeyEvent.VK_S:
		case KeyEvent.VK_T:
		case KeyEvent.VK_U:
		case KeyEvent.VK_V:
		case KeyEvent.VK_W:
		case KeyEvent.VK_X:
		case KeyEvent.VK_Y:
		case KeyEvent.VK_Z:
		case KeyEvent.VK_OPEN_BRACKET:
		case KeyEvent.VK_CLOSE_BRACKET:
		case KeyEvent.VK_BACK_SLASH:
		case KeyEvent.VK_BRACERIGHT:
		case KeyEvent.VK_SEMICOLON:
		case KeyEvent.VK_QUOTE:
		case KeyEvent.VK_COMMA:
		case KeyEvent.VK_PERIOD:
		case KeyEvent.VK_SLASH:
		case KeyEvent.VK_SPACE:
		case KeyEvent.VK_NUMPAD0:
		case KeyEvent.VK_NUMPAD1:
		case KeyEvent.VK_NUMPAD2:
		case KeyEvent.VK_NUMPAD3:
		case KeyEvent.VK_NUMPAD4:
		case KeyEvent.VK_NUMPAD5:
		case KeyEvent.VK_NUMPAD6:
		case KeyEvent.VK_NUMPAD7:
		case KeyEvent.VK_NUMPAD8:
		case KeyEvent.VK_NUMPAD9:
		case KeyEvent.VK_ADD:
		case KeyEvent.VK_SUBTRACT:
		case KeyEvent.VK_MULTIPLY:
		case KeyEvent.VK_DIVIDE:
		case KeyEvent.VK_DECIMAL:
			return true;
		default:
			return false;
		}
	}
}
